/*
 * World.java
 *
 * Created on June 30, 2008, 12:04 AM
 */

package world;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import creature.Creature;
import creature.Creature4;
import java.awt.Point;
import java.util.Vector;


/**
 *
 * @author  leadiv
 */
public class World extends javax.swing.JPanel implements Runnable {
    private int width;
    private int height;
    private Vector<Creature> population;
    private Creature[] world;
    private double popPercent = .1; // default is 10% of the world size
    private boolean simMode = false;
    public final static Point[] MOVE = {
        new Point(-1,1),
        new Point(0,1),
        new Point(1,1),
        new Point(-1,0),
        new Point(1,0),
        new Point(-1,-1),
        new Point(0,-1),
        new Point(1,-1)
    };
    private int stats_birth;
    private int stats_death;

    /** Creates new form World */
    public World() {
        super();
        width = getWidth() > 0 ? getWidth() : 100;
        height = getHeight() > 0 ? getHeight() : 100;
        world = new Creature[width * height];
        
        for(int i=0; i<world.length; i++)
        {
            world[i] = null;
        }
        
        setSize(width,height);
        
        populate();
        initComponents();
    }

    public World(int width, int height)
    {
        super();
        this.width = width;
        this.height = height;
        world = new Creature[width * height];
        
        for(int i=0; i<world.length; i++)
        {
            world[i] = null;
        }
        
        setSize(width, height);
        
        populate();
        initComponents();
    }
    
    public void update()
    {
        int curKey;
        int i;

        for(i=0;i<population.size(); i++)
        {
            curKey = (int)(Math.random() * population.size());
            if(population.get(curKey) != null)
            {
                population.get(curKey).move(this);
            }
        }

    }
    
    public void populate() 
    {
        int popCount = (int)(this.width * this.height * this.popPercent);
        
        population = new Vector<Creature>();
        for(int i=0; i<popCount; i++)
        {
            int x = (int) (Math.random() * width);
            int y = (int) (Math.random() * height);
            int keyid = (y * width) + x;
            
            if(world[keyid] == null) {
                world[keyid] = new Creature4(x, y, keyid);
                population.add(world[keyid]);
            }
        }
        this.stats_birth = population.size();
    }

    public int birth(int x, int y) {
        final int CUR_W = 1;
        final int CUR_H = 1;
        final int OFFSET = 0;

        // NEED TO MAKE SURE THE NEW XY IS IN THE WORLD.
        // X: 0 to width - 1
        // Y: 0 to height - 1
        x = x < 0 ? this.width - 1 : x;
        y = y < 0 ? this.height - 1 : y;
        x %= this.width;
        y %= this.height;

        // does a creature occupy the new space already?
        int newKey = (y * width) + x;
        if(world[newKey] != null) {
            return -1;
        }

        int keyid = (y * width) + x;
        world[keyid] = new Creature4(x, y, keyid);
        population.add(world[keyid]);

        repaint(x, y, CUR_W+OFFSET, CUR_H+OFFSET);

        this.stats_birth++;
        return keyid;
    }

    public void death(int x, int y, int id, Creature c) {
        final int CUR_W = 1;
        final int CUR_H = 1;
        final int OFFSET = 0;
        
        this.world[id] = null;
        population.remove(c);

        repaint(x, y, CUR_W+OFFSET, CUR_H+OFFSET);
    }

    public boolean place(int x, int y, int id)
    {
        final int CUR_W = 1;
        final int CUR_H = 1;
        final int OFFSET = 0;
        
        // NEED TO MAKE SURE THE NEW XY IS IN THE WORLD.
        // X: 0 to width - 1
        // Y: 0 to height - 1
        x = x < 0 ? this.width - 1 : x;
        y = y < 0 ? this.height - 1 : y;
        x %= this.width;
        y %= this.height;
        
        // does this creature actually exist?
        if(world[id] == null) {
            return false;
        }
        
        // does a creature occupy the new space already?
        int newKey = (y * width) + x;
        if(world[newKey] != null) {
            return false;
        }
        
        // are we trying to place this creature in the same exact place?
        if(newKey == id) {
            return true;
        }
        
        // this is a valid Creature...now lets move it!
        Creature old = world[id];
        world[id] = null;
  
        int oldX, oldY;
        oldX = old.getX();
        oldY = old.getY();
        
        repaint(oldX, oldY, CUR_W+OFFSET, CUR_H+OFFSET);
                
        old.setX(x);
        old.setY(y);
        old.setId(newKey);
        world[newKey] = old;
        
        repaint(x, y, CUR_W+OFFSET, CUR_H+OFFSET);

        this.stats_death++;
        
        return true;
    }
    
    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        int i;

        g.setColor(Color.BLACK);
        g.fillRect(0,0,width,height);

        for(i=0; i<population.size(); i++) {
            try {
                population.get(i).draw(g);
            } catch(java.lang.ArrayIndexOutOfBoundsException aioobe) {
                // continue on our merry way...
            }
        }

    }

    public Point fixPosition(int x, int y) {
        x = x < 0 ? this.width - 1 : x;
        y = y < 0 ? this.height - 1 : y;
        x %= this.width;
        y %= this.height;
        
        return new Point(x, y);
    }
    
    public Creature lookHere(int x, int y) {
        Point pos = fixPosition(x, y);
        
        return world[((int)pos.getY() * width) + (int)pos.getX()];
    }
    
    public Color getpix(int x, int y) {
        Point pos = fixPosition(x, y);
        x = (int)pos.getX();
        y = (int)pos.getY();
        
        if(world[(y * width) + x] == null) {
            return Color.BLACK;
        }
        
        return world[(y * width) + x].getSkinColor();
    }
    
    @Override
    public Dimension getPreferredSize() {
        return new Dimension(this.width, this.height);
    }
    
    public void setSimMode(boolean sm) {
        simMode = sm;
    }
    
    public boolean getSimMode() {
        return simMode;
    }
    
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        setOpaque(false);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 400, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 300, Short.MAX_VALUE)
        );
    }// </editor-fold>//GEN-END:initComponents

    public void run() {
        simMode = true;
        while(simMode) {
            this.update();
        }
        System.out.println("Population Stats (Size | Births | Deaths): " +
                population.size() + " | " +
                this.stats_birth + " | " +
                this.stats_death + " | Diff: " +
                (this.stats_birth - this.stats_death));
    }


    // Variables declaration - do not modify//GEN-BEGIN:variables
    // End of variables declaration//GEN-END:variables
}